/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dkvklocka;



import java.util.Observable;
import java.util.Observer;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.*;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;

import javafx.scene.control.Label;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Duration;


/**
 *
 * @author max.gabrielsson
 */
public class DkvKlocka extends Application implements Observer{
    private static final String DRINK_START = "S";
    private static final String RESET = "R";
    private static final String DRINK_STOP = "T";
    private static final String UP = "U";
    private static final String DOWN = "D";
  /*  static{
        String path ="";
        try {
            path = (new java.io.File(".").getCanonicalPath());
            System.out.println(path);
        } catch (IOException ex) {
            Logger.getLogger(DkvKlocka.class.getName()).log(Level.SEVERE, null, ex);
        }
        Runtime.getRuntime().load(path +"\\rxtxParallel.dll");
        Runtime.getRuntime().load(path +"\\rxtxSerial.dll");
    }
*/
    private Drinker drinker;
    private Stage primaryStage;
    private Label timeLabel;
    private Label textLabel;
    private String valueBuffer = ""; //for buffering up the values
    private Timeline timeTimeline;
    private Timeline textTimeline;
    private ISerialListener serialListener;

    //private FloatProperty timeMillis = new SimpleFloatProperty(Float.);
    private long deltaMillis;
    private StringProperty timeMillis = new SimpleStringProperty();
    private long startMillis;
    private int resultPointer = 0;
    private boolean resultDirty = false; 
    
    public static void main(String[] args) throws Exception {
		launch(args);       
                
    }

    @Override
    public void stop() throws Exception {
        serialListener.close();
        super.stop();
        
    }
    
    
    
    
    
    
    @Override
    public void start(Stage stage) {
        primaryStage = stage;
        drinker = new Drinker();
        StackPane root = new StackPane();
        root.setId("timer");
     
        timeMillis.set(getPublishMillis("")); //00:000
  
        //stackPane.getChildren().add(root);
        //stackPane.getChildren().add(root);
        Scene scene = new Scene(root);
        scene.setOnKeyPressed(new EventHandler<KeyEvent>() {

            @Override
            public void handle(KeyEvent arg0) {
               if(arg0.isAltDown()){
                   fullScreen();
               } else {
                   
                   if(arg0.getText()!=null&&!arg0.getText().equals("")){
                      // serialListener.setSetting(DkvPropUtils.getProperty("dkvklocka." + arg0.getText()));
                        textLabel.setText(DkvPropUtils.getProperty("dkvklocka." + arg0.getText()));
                        textTimeline.stop();
                        textTimeline.playFromStart();
                   }
               }
            }
        });
        
           
        
        primaryStage.setTitle(DkvPropUtils.getProperty("dkvklocka.title"));
        //primaryStage.setFullScreen(true);
        primaryStage.setScene(scene);
        
        primaryStage.getScene().setFill(Color.web(DkvPropUtils.getProperty("dkvklocka.background.color", "#FFFFFF")));
        primaryStage.getScene().getStylesheets().add(DkvKlocka.class.getResource("demo.css").toExternalForm());
        primaryStage.show();
    
        
       
        serialListener = new DummySerialListener();//new SerialListener();
        serialListener.initialize();
        
        serialListener.addObserver(this);
        timeLabel = new Label();
        timeLabel.textProperty().bind(timeMillis);
        timeLabel.setFont(new Font(DkvPropUtils.getProperty("dkvklocka.timefont.family", "Consolas"),Integer.valueOf(DkvPropUtils.getProperty("dkvklocka.timefont.size", "200"))));
        timeLabel.setTextFill(Color.web(DkvPropUtils.getProperty("dkvklocka.timefont.color", "#FAEBD7")));
        
        
        textLabel = new Label();
        //textLabel.textProperty().bind(textMessage);
        StackPane.setMargin(textLabel, new Insets(20));
        
        StackPane.setAlignment(textLabel, Pos.TOP_CENTER);
        textLabel.setFont(new Font(DkvPropUtils.getProperty("dkvklocka.textfont.family", "Consolas"),Integer.valueOf(DkvPropUtils.getProperty("dkvklocka.textfont.size", "100"))));
        textLabel.setTextFill(Color.web(DkvPropUtils.getProperty("dkvklocka.textfont.color", "#FAEBD7")));
        
        //label.setAlignment(Pos.CENTER);
        //root.setId("klocka");
        //String s = DkvKlocka.class.getResource("demo.css").toExternalForm();
      //  root.setStyle(s);
        root.getChildren().add(textLabel);
        root.getChildren().add(timeLabel);
        
       
        initTimeTimeline();
        initTextTimeline();
       // stage.setScene(new Scene(stackPane));
        
        //SerialListener serialListener = new SerialListener();
       // serialListener.initializeSerial();
        
       
  
    }
    
    private void fullScreen() {
        primaryStage.setFullScreen(true);
    }

    @Override
    public void update(Observable o, Object o1) {
        final String s = ((ISerialListener)o).getValue();
        Runnable updateInfo = new Runnable() {

            @Override
            public void run() {
                
                updateGui(s);
            }
        };

          
         
         Platform.runLater(updateInfo);
    }

    private String getPublishMillis(String stringOfMillis) {
        if(stringOfMillis == null || "".equals(stringOfMillis)){
            stringOfMillis = "00000";
        }
        while(stringOfMillis.length()<5){
            stringOfMillis = "0" + stringOfMillis; //00001
        }
        stringOfMillis=stringOfMillis.substring(0,stringOfMillis.length()-3)+DkvPropUtils.getProperty("dkvklocka.time.separator") +stringOfMillis.substring(stringOfMillis.length()-3,stringOfMillis.length());
        return stringOfMillis.substring(stringOfMillis.length()-6);
    }

 
 
 
    private void updateGui(String value) {
        int breakIndex = 0; //for knowing where to break the values
        String data = ""; 
        /*
         * (7:33:09 PM) Max: men min byte[] som jag tar emot (och skickar ut som sträng) ser typiskt ut "34\r\nT 23423\r\n"
(7:33:15 PM) Max: och det är \r\n som är slutet
(7:33:30 PM) Max: början är alltid en bokstav
(7:33:36 PM) Mattias: Ok, då är det indexOf det.
(7:33:59 PM) Mattias: Så först breakIndex = buffert.indexOf("\r\n");
(7:34:23 PM) Mattias: sedan data = buffert.substring(0,breakIndex).
(7:34:35 PM) Mattias: Sedan buffert.delete(0,breakIndex).
(7:34:55 PM) Mattias: Kör en while(breakIndex >= 0) också om det kommer flera i samma läsning.
(7:34:56 PM) Max: det blir kanon
(7:35:11 PM) Max: det kan komma flera eller färre
(7:35:15 PM) Max: 0-n
(7:35:16 PM) Mattias: Japp.
(7:35:25 PM) Mattias: Så det där kör du efter varje läsning.
(7:35:40 PM) Max: ja just, och uppdaterar det jag behöver efter varje läsning
(7:35:48 PM) Max: Fasen mattias, du bygger ju detta åt mig. :)
(7:35:57 PM) Mattias: Har du en while((breakIndex = buffert.indexOf("\r\n")) >=0) blir det bra.
         */
        valueBuffer +=value;
        while((breakIndex = valueBuffer.indexOf("|")) >=0){
            
            breakIndex = valueBuffer.indexOf("|");
            data = valueBuffer.substring(0, breakIndex);
            valueBuffer = valueBuffer.substring(breakIndex + 1);
            if(data.equals(DRINK_START)){
                drinkStart();
            } else if(data.equals(RESET)) {
                reset();
            } else if(data.startsWith(DRINK_STOP)){
                oneFinnish(data);
            } else if (data.equals(DOWN)){
                step(-1);
            } else if (data.equals(UP)){
                step(1);
            } else {
                showError(data);
            }
        }

    }

    private void drinkStart() {
        
        startMillis = System.currentTimeMillis();
        timeTimeline.play();
    }
    
    private void reset() {
        deltaMillis = 0;
        drinker = new Drinker();
        initTimeTimeline();
        deltaMillis = 0;
        timeMillis.set(getPublishMillis(""));
        timeLabel.textProperty().bind(timeMillis);
    }

    private void oneFinnish(String value) {
        timeTimeline.stop();
        Long l = Long.parseLong(value.trim().substring(1));
        drinker.getResultList().add(l);
        if(resultDirty){
            resultPointer = drinker.getResultList().indexOf(l);
            resultDirty = false;
        }
        timeLabel.textProperty().unbind();
        timeLabel.setText(getPublishMillis(drinker.getResultList().get(resultPointer).toString()));
    }

    

    
    private void initTimeTimeline() {
        if (timeTimeline != null) {
            timeTimeline.stop();
        }
        
        timeTimeline = new Timeline();
        
        timeTimeline.setCycleCount(Timeline.INDEFINITE);
       
        KeyFrame k =  new KeyFrame(Duration.millis(47),new EventHandler<ActionEvent>() {

            public void handle(ActionEvent event) {
                deltaMillis=deltaMillis+47;
                String s = String.valueOf(deltaMillis);
             
                timeMillis.set(getPublishMillis(s));
            }
        });
        timeTimeline.getKeyFrames().add(k);
    }
    
    private void initTextTimeline() {
        if(textTimeline!=null) {
            textTimeline.stop();
        }
         textTimeline = new Timeline();
        
        textTimeline.setCycleCount(1);
        
//        KeyFrame k =  new KeyFrame(Duration.millis(10),new EventHandler<ActionEvent>() {
//
//            public void handle(ActionEvent event) {
//                
//                textMessage.set(text);
//            }
//        });
      
        
        KeyValue v = new KeyValue(textLabel.textProperty(), "");
        KeyFrame k = new KeyFrame(Duration.seconds(Integer.valueOf(DkvPropUtils.getProperty("dkvklocka.textfont.duration.seconds", "2"))), v);
        textTimeline.getKeyFrames().add(k);
        
    }

    

    private void step(int i) {
        if(drinker.getResultList().isEmpty()){
           return;
        }
        timeTimeline.stop();
        timeLabel.textProperty().unbind();
        
        if((resultPointer+i)<0 || (resultPointer+i)==drinker.getResultList().size()){
            resultPointer = drinker.getResultList().size();
            
            resultDirty=true;
            timeTimeline.play();
            deltaMillis = System.currentTimeMillis()-startMillis;
            String s = String.valueOf(deltaMillis);

            timeMillis.set(getPublishMillis(s));
            timeLabel.textProperty().bind(timeMillis);
            return;
        } else if((resultPointer+i)>drinker.getResultList().size()){
            resultPointer = 0;
            
        } else {
            resultPointer += i;
        }
       
        timeLabel.setText(getPublishMillis(drinker.getResultList().get(resultPointer).toString()));
    }

    private void showError(String data) {
       timeTimeline.stop();
       timeLabel.textProperty().unbind();
       timeLabel.setText(data);
    }
   
}